/**
 * Copyright (C), 2001-2031, www.bosssof.com.cn
 * FileName: Enum.java
 * Author: YuXingZh
 * Date: 16/5/2024 上午10:42
 * Description:
 * <p>
 * History:
 * Date          Author   Version  Desc
 * 2024-01-01    bosssoft  1.0.0   initialize this file
 */
package org.boss.server;

import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.util.concurrent.GlobalEventExecutor;
import org.boss.exception.BizCodeEnum;
import org.boss.exception.CmdException;
import org.boss.protocol.Protocol;
import org.boss.util.CryptUtil;
import org.boss.util.FileUtil;
import org.boss.util.ProtocolUtil;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.charset.Charset;

import static org.boss.cont.CmdCont.*;

/**
 * @className: protocol
 * @description: 定义服务端处理器
 * @author: YuXingZh
 * @date: 15/5/2024下午10:38
 * @since 1.0
 **/
public class FileServerHandler extends SimpleChannelInboundHandler<String> {
    private static final ChannelGroup CHANNEL_GROUP = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
    private static final String FILE_PREFIX = ".\\store\\store";
    private static final String BEGIN = "\"开始接收中\"";
    private static final String END = "\"接收完成\"";

    /*
     * 接收消息处理
     * @author YuXingZh
     * @date 2024/05/17 08:40
     *
     * @param ctx
     * @param msg
     * @return void
     */
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
        // 封装命令
        Protocol protocol = ProtocolUtil.convert(msg);

        // 获取发送IP
        Channel channel = ctx.channel();
        InetSocketAddress localAddress = (InetSocketAddress) channel.remoteAddress();
        int localPort = localAddress.getPort();
        String fromFileAddress = FILE_PREFIX + localPort + "\\" + protocol.getAddress();

        CHANNEL_GROUP.forEach(ch -> {
            // 获取接收IP
            InetSocketAddress remoteAddress = (InetSocketAddress) ch.remoteAddress();
            int port = remoteAddress.getPort();
            String toFileAddress = FILE_PREFIX + port + "\\" + protocol.getAddress();

            if (channel != ch && StrUtil.equals(SEND, protocol.getCmd())) {
                if (StrUtil.equals(ALL, protocol.getType()) || (NumberUtil.isNumber(protocol.getType()) && NumberUtil.equals(port, NumberUtil.parseInt(protocol.getType())))) {
                    ch.writeAndFlush(BEGIN + "\r\n");
                    try {
                        // 读取文件
                        byte[] bytes = FileUtil.readFile(fromFileAddress);
                        // 加密文件
                        byte[] encryptFile = CryptUtil.encrypt(bytes, FileUtil.chooseKeyByFileType(fromFileAddress));
                        // 写入文件
                        FileUtil.writeFile(toFileAddress, encryptFile);
                        ch.writeAndFlush(END + "\r\n");
                    } catch (IOException e) {
                        ch.writeAndFlush(BizCodeEnum.FILE_TRANSFER_ERROR.getDescription() + "\r\n");
                    }
                } else {
                    ch.writeAndFlush(BizCodeEnum.CMD_ERROR.getDescription() + "\r\n");
                }
            } else if (channel == ch && StrUtil.equals(SHOW, protocol.getCmd())) {
                // SHOW命令
                try {
                    // 读取本地文件
                    byte[] bytes = FileUtil.readFile(toFileAddress);
                    // 解密
                    byte[] content = CryptUtil.decrypt(bytes, FileUtil.chooseKeyByFileType(fromFileAddress));
                    ch.writeAndFlush(StrUtil.str(content, Charset.defaultCharset()));
                } catch (IOException e) {
                    ch.writeAndFlush(BizCodeEnum.FILE_TRANSFER_ERROR.getDescription() + "\r\n");
                }
            } else {
                ch.writeAndFlush(BizCodeEnum.CMD_ERROR.getDescription() + "\r\n");
            }
        });
    }

    /*
     * 客户端连接建立
     * @author YuXingZh
     * @date 2024/05/17 08:41
     *
     * @param ctx
     * @return
     */
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        // 获取连接对象
        Channel channel = ctx.channel();
        SocketAddress socketAddress = channel.remoteAddress();
        CHANNEL_GROUP.writeAndFlush("[ 客户端 ] - " + socketAddress + " 加入\n");
        // 创建文件夹
        FileUtil.createFileStore(socketAddress);
        //加入连接组
        CHANNEL_GROUP.add(channel);
    }

    /*
     * 客户端连接断开
     * @author YuXingZh
     * @date 2024/05/17 08:41
     *
     * @param ctx
     * @return void
     */
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        Channel channel = ctx.channel();
        CHANNEL_GROUP.writeAndFlush("[ 客户端 ] - " + channel.remoteAddress() + "离开\n");
        System.out.println(channel.remoteAddress() + " 上线");
    }

    /*
     * 服务端提示上线
     * @author YuXingZh
     * @date 2024/05/17 08:42
     *
     * @param ctx
     * @return void
     */
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        Channel channel = ctx.channel();
        System.out.println(channel.remoteAddress() + " 上线");
    }

    /*
     * 客户端提示下线
     * @author YuXingZh
     * @date 2024/05/17 08:42
     *
     * @param ctx
     * @return void
     */
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        Channel channel = ctx.channel();
        System.out.println(channel.remoteAddress() + " 下线");
    }

    /*
     * 服务端提示与客户端断开连接
     * @author YuXingZh
     * @date 2024/05/17 08:42
     *
     * @param ctx
     * @param cause
     * @return void
     */
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        //关闭与客户端连接
        Channel channel = ctx.channel();
        System.out.println(channel.remoteAddress() + " 关闭与客户端连接");
        ctx.close();
    }
}
